package main

import (
	"context"
	"errors"
	"fmt"
	"golang.org/x/sync/errgroup"
	"google.golang.org/grpc"
	"net"
	"os"
	"os/signal"
)

type App struct {
	listener net.Listener
	server *grpc.Server
	eg *errgroup.Group
	ctx context.Context
}

func NewApp( ctx context.Context, listener net.Listener, server *grpc.Server) *App {
	eg, ctx := errgroup.WithContext(ctx)
	return &App{
		listener: listener,
		server: server,
		eg: eg,
		ctx: ctx,
	}
}

func (a *App) Run() error {

	a.cancelWithSignal()
	a.startServer()

	return a.eg.Wait()
}

func (a *App) cancelWithSignal()  {
	sigChan := make(chan os.Signal, 1)
	a.eg.Go(func() error {
		signal.Notify(sigChan, os.Kill, os.Interrupt)
		defer close(sigChan)
		defer signal.Stop(sigChan)
		select {
		case sig := <-sigChan: return errors.New(fmt.Sprintf("cause by %v", sig))
		case <- a.ctx.Done(): return errors.New(fmt.Sprintf("cause by other"))
		}
	})
}

func (a *App) startServer()  {
	a.eg.Go(func() error {
		return a.server.Serve(a.listener)
	})

	a.eg.Go(func() error {
		select {
		case <- a.ctx.Done():
			a.server.GracefulStop()
			return nil
		}
	})
}